/**
 *  HttpClient.cpp
 *
 *  Copyright (C) 2008  David Andrs <pda@jasnapaka.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "StdAfx.h"
#include "mLasq.h"
#include "HttpClient.h"
#include "helpers.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CNResponse::CNResponse() {
}

CString CNResponse::GetResponseValue(const CString &name) {
	CString value;
	if (Data.Lookup(name, value)) {
	}
	return value;
}

void CNResponse::ProcessBuffer(char *buffer, int len) {
	if (len >= 2048) return;			// to be safe

	// NOTE: pretty stupid - it supposes that responses will be very small (less than 2KiB)
	static char tmp[2048] = { 0 };

	strncpy(tmp, buffer, len);
	tmp[len] = '\0';				// terminate the string
//	LOG1(1, "buf: '%s'", tmp);

	char *seps = "\n";

	char *start = tmp + 0;
	char *token = strtok(start, seps);
	while (token != NULL) {
		char *equal = strchr(token, '=');
		if (equal != NULL) {
			*equal = '\0';
			equal++;

			CString key = CharToWChar(token);
			CString value = CharToWChar(equal);

			Data.SetAt(key, value);
		}

		token = strtok(NULL, seps);
	}

}

void CNResponse::Finished() {
}

///////////////////////////////////////////////////////////////////////

static void XMLCALL
startElement(void *userData, const char *name, const char **attr) {
	CXmlResponse *res = (CXmlResponse *) userData;
	res->OnStartElement(name, attr);
}

static void XMLCALL
endElement(void *userData, const char *name) {
	CXmlResponse *res = (CXmlResponse *) userData;
	res->OnEndElement(name);
}

static void XMLCALL
charDataHandler(void *userData, const XML_Char *s, int len) {
	CXmlResponse *res = (CXmlResponse *) userData;
	res->OnCharDataHandler(s, len);
}

CXmlResponse::CXmlResponse() {
	// reset temp node
	Parser = XML_ParserCreate(NULL);
	XML_SetUserData(Parser, this);
	XML_SetXmlDeclHandler(Parser, NULL);
	XML_SetElementHandler(Parser, startElement, endElement);
	XML_SetCharacterDataHandler(Parser, charDataHandler);
}

CXmlResponse::~CXmlResponse() {
	XML_ParserFree(Parser);
}

void CXmlResponse::ProcessBuffer(char *buffer, int len) {
	BOOL done = FALSE;
	if (XML_Parse(Parser, buffer, len, done) == XML_STATUS_ERROR) {
		// error
	}
}

void CXmlResponse::Finished() {
}

//////////////////////////////////////////////////////////////////////

CPlaylistResponse::CPlaylistResponse() {
	State = PR_NONE;
	Entry = NULL;
}

void CPlaylistResponse::OnStartElement(const char *name, const char **attr) {
	if (Entry == NULL) {
		if (strcmp(name, "title") == 0) State = PR_TITLE;
		else if (strcmp(name, "track") == 0) {
			Entry = new CPlaylistEntry();
		}
		else State = PR_NONE;
	}
	else {
		if (strcmp(name, "id") == 0)			State = PR_TRACK_ID;
		else if (strcmp(name, "title") == 0)	State = PR_TRACK_TITLE;
		else if (strcmp(name, "location") == 0) State = PR_TRACK_LOCATION;
		else if (strcmp(name, "album") == 0)	State = PR_TRACK_ALBUM;
		else if (strcmp(name, "creator") == 0)	State = PR_TRACK_CREATOR;
		else if (strcmp(name, "duration") == 0) State = PR_TRACK_DURATION;
		else if (strcmp(name, "image") == 0)	State = PR_TRACK_IMAGE;
		else State = PR_NONE;
	}
}

void CPlaylistResponse::OnEndElement(const char *name) {
	if (strcmp(name, "track") == 0) {
		Playlist.AddTail(Entry);
		Entry = NULL;
		State = PR_NONE;
	}
}

void CPlaylistResponse::OnCharDataHandler(const XML_Char *s, int len) {
	CString str;
	str = CharToWChar(s, len, CP_UTF8);

	switch (State) {
		case PR_TITLE: Title = str; break;
		case PR_TRACK_ID: Entry->Id = str; break;
		case PR_TRACK_TITLE: Entry->Title = str; break;
		case PR_TRACK_ALBUM: Entry->Album = str; break;
		case PR_TRACK_LOCATION: Entry->Location = str; break;
		case PR_TRACK_CREATOR: Entry->Artist = str; break;
		case PR_TRACK_IMAGE: Entry->Image = str; break;
		case PR_TRACK_DURATION: swscanf(str, _T("%d"), &Entry->Duration); break;
	}

	State = PR_NONE;
}


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CHttpClient::CHttpClient(const CString &hostName, int port/* = 80*/) {
	HostName = hostName;
	Port = port;

	Request = NULL;
	Response = NULL;
}

CHttpClient::~CHttpClient() {
	Close();
}

void CHttpClient::Close() {
	if (Request != NULL) {
		delete Request;
		Request = NULL;
	}

	if (Response != NULL) {
		delete Response;
		Response = NULL;
	}
}

BOOL CHttpClient::SendRequest(const CString &request) {
	LOG0(5, "CHttpClient::SendRequest()");

	BOOL ret = FALSE;

	if (HttpConnection.Open(INET_SERVICE_HTTP, HostName, Port)) {
		Request = HttpConnection.CreateRequest(request);
		if (Request != NULL) {
			HttpConnection.SendRequest(Request);
			Response = HttpConnection.ReceiveResponse();
			ret = (Response != NULL);
		}
	}

	return ret;
}

BOOL CHttpClient::ReceiveResponse(CHttpResponseBody *response) {
	LOG0(5, "CHttpClient::ReceiveResponse()");

	DWORD statusCode = Response->GetStatusCode();
	if (statusCode == HTTP_STATUS_OK) {
		char buffer[1024];
		int numRead;

		while ((numRead = HttpConnection.Read(buffer + 0, sizeof(buffer) - 1)) > 0) {
			// process read data
			if (response != NULL)
				response->ProcessBuffer(buffer, numRead);
		}
		response->Finished();

		return TRUE;
	}
	else {
		Close();
		return FALSE;
	}


/*
	DWORD dwRet;
	if (!File->QueryInfoStatusCode(dwRet))
		return FALSE;

	if (dwRet == HTTP_STATUS_OK) {
		char buffer[1024];
		int numRead;

		while ((numRead = File->Read(buffer, sizeof(buffer) - 1 )) > 0) {
			// process read data
			if (response != NULL)
				response->ProcessBuffer(buffer, numRead);
		}
		response->Finished();

		return TRUE;
	}
	else {
		Close();
		return FALSE;
	}
*/

}


